1 Introducción

Este documento presenta un análisis exploratorio completo del conjunto de datos que abarca información del período 2009-2023.

1.1 Carga de Datos

datos <- read.csv("datos_combinados.csv", 
                  header = TRUE, 
                  stringsAsFactors = FALSE,
                  fileEncoding = "UTF-8")

Dataset cargado exitosamente


2 Descripción General del Conjunto de Datos

2.1 Dimensiones del Conjunto

n_observaciones <- nrow(datos)
n_variables <- ncol(datos)

Resumen del Dataset:

  • Observaciones: 41,623 registros
  • Variables: 33 columnas
  • Período: 2009-2023

2.2 Significado y Tipo de cada Variable

2.2.1 Diccionario de Datos

# Diccionario de datos - Significado de cada variable
diccionario_variables <- data.frame(
  Variable = c(
    "DEPREG", "MUPREG", "MESREG", "AÑOREG",
    "DEPOCU", "MUPOCU", "AREAG", 
    "SEXO", "DIAOCU", "MESOCU", "AÑOOCU",
    "TIPAR", "CLAPAR", "VIAPAR",
    "SEMGES", "EDADM",
    "DEPREM", "MUPREM", "GRETNM", "ESCIVM", 
    "NACIOM", "OCUPAM", "ESCOLAM",
    "PAISREM", "PUEBLOPM", "CIUOMAD", "NACIONM",
    "CAUDEF", "ASISREC", "SITIOOCU",
    "TOHITE", "TOHINM", "TOHIVI"
  ),
  Significado = c(
    "Departamento de registro",
    "Municipio de registro",
    "Mes de registro",
    "Año de registro",
    "Departamento de ocurrencia",
    "Municipio de ocurrencia",
    "Área geográfica (1=Urbana, 2=Rural)",
    "Sexo del fallecido (1=Masculino, 2=Femenino, 9=No especificado)",
    "Día de ocurrencia",
    "Mes de ocurrencia",
    "Año de ocurrencia",
    "Tipo de parto",
    "Clasificación del parto",
    "Vía del parto",
    "Semanas de gestación",
    "Edad de la madre (en años)",
    "Departamento de residencia de la madre",
    "Municipio de residencia de la madre",
    "Grupo étnico de la madre",
    "Estado civil de la madre",
    "Nacionalidad de la madre",
    "Ocupación de la madre",
    "Escolaridad de la madre (años de estudio)",
    "País de residencia de la madre",
    "Pueblo/comunidad indígena de la madre",
    "Ciudad o municipio de residencia de la madre",
    "Nacionalidad de la madre (código)",
    "Causa de defunción (código CIE-10)",
    "Asistencia recibida (1=Sí, 2=No)",
    "Sitio de ocurrencia del parto",
    "Total de hijos tenidos",
    "Total de hijos nacidos muertos",
    "Total de hijos nacidos vivos"
  ),
  stringsAsFactors = FALSE
)

diccionario_variables %>%
  kable(
    caption = "Tabla 1: Diccionario de Datos - Significado de Variables",
    col.names = c("Variable", "Descripción/Significado"),
    align = c('l', 'l')
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = TRUE,
    position = "center"
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#3498db") %>%
  scroll_box(width = "100%", height = "500px")
Tabla 1: Diccionario de Datos - Significado de Variables
Variable Descripción/Significado
DEPREG Departamento de registro
MUPREG Municipio de registro
MESREG Mes de registro
AÑOREG Año de registro
DEPOCU Departamento de ocurrencia
MUPOCU Municipio de ocurrencia
AREAG Área geográfica (1=Urbana, 2=Rural)
SEXO Sexo del fallecido (1=Masculino, 2=Femenino, 9=No especificado)
DIAOCU Día de ocurrencia
MESOCU Mes de ocurrencia
AÑOOCU Año de ocurrencia
TIPAR Tipo de parto
CLAPAR Clasificación del parto
VIAPAR Vía del parto
SEMGES Semanas de gestación
EDADM Edad de la madre (en años)
DEPREM Departamento de residencia de la madre
MUPREM Municipio de residencia de la madre
GRETNM Grupo étnico de la madre
ESCIVM Estado civil de la madre
NACIOM Nacionalidad de la madre
OCUPAM Ocupación de la madre
ESCOLAM Escolaridad de la madre (años de estudio)
PAISREM País de residencia de la madre
PUEBLOPM Pueblo/comunidad indígena de la madre
CIUOMAD Ciudad o municipio de residencia de la madre
NACIONM Nacionalidad de la madre (código)
CAUDEF Causa de defunción (código CIE-10)
ASISREC Asistencia recibida (1=Sí, 2=No)
SITIOOCU Sitio de ocurrencia del parto
TOHITE Total de hijos tenidos
TOHINM Total de hijos nacidos muertos
TOHIVI Total de hijos nacidos vivos

2.2.2 Clasificación Estadística de Variables

# Función para clasificar variables
clasificar_variable <- function(variable, nombre_var) {
  if(is.character(variable)) {
    return("Cualitativa - Nominal")
  }
  
  if(is.numeric(variable)) {
    valores_unicos <- length(unique(na.omit(variable)))
    total_valores <- length(na.omit(variable))
    ratio <- valores_unicos / total_valores
    
    variables_discretas <- c("SEXO", "DEPREG", "MUPREG", "MESREG", "DEPOCU", 
                             "MUPOCU", "AREAG", "TIPAR", "CLAPAR", "DEPREM",
                             "MUPREM", "GRETNM", "ESCIVM", "NACIOM", "OCUPAM",
                             "ASISREC", "SITIOOCU", "TOHITE", "TOHINM", "TOHIVI",
                             "VIAPAR", "ESCOLAM", "PAISREM", "PUEBLOPM", "NACIONM",
                             "DIAOCU", "MESOCU", "AÑOOCU", "AÑOREG")
    
    variables_continuas <- c("EDADM", "SEMGES")
    
    if(nombre_var %in% variables_discretas) {
      return("Cuantitativa - Discreta")
    } else if(nombre_var %in% variables_continuas) {
      return("Cuantitativa - Continua")
    } else {
      if(ratio < 0.05 || valores_unicos < 50) {
        return("Cuantitativa - Discreta")
      } else {
        return("Cuantitativa - Continua")
      }
    }
  }
  return("Otro")
}

# Crear tabla de información de variables
info_variables <- data.frame(
  Variable = names(datos),
  Tipo_R = sapply(datos, class),
  Clasificacion = sapply(names(datos), function(nom) {
    clasificar_variable(datos[[nom]], nom)
  }),
  Valores_Unicos = sapply(datos, function(x) length(unique(na.omit(x)))),
  Valores_NA = sapply(datos, function(x) sum(is.na(x))),
  Porcentaje_NA = round(sapply(datos, function(x) sum(is.na(x)) / length(x) * 100), 2)
)

# Mostrar tabla con formato mejorado
info_variables %>%
  kable(
    caption = "Tabla 2: Clasificación y Características de las Variables",
    col.names = c("Variable", "Tipo en R", "Clasificación Estadística", 
                  "Valores Únicos", "Valores NA", "% NA"),
    align = c('l', 'c', 'l', 'r', 'r', 'r')
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE,
    position = "center"
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#3498db") %>%
  scroll_box(width = "100%", height = "500px")
Tabla 2: Clasificación y Características de las Variables
Variable Tipo en R Clasificación Estadística Valores Únicos Valores NA % NA
DEPREG DEPREG numeric Cuantitativa - Discreta 22 0 0.00
MUPREG MUPREG integer Cuantitativa - Discreta 335 0 0.00
MESREG MESREG numeric Cuantitativa - Discreta 12 0 0.00
AÑOREG AÑOREG numeric Cuantitativa - Discreta 15 0 0.00
DEPOCU DEPOCU numeric Cuantitativa - Discreta 22 0 0.00
MUPOCU MUPOCU integer Cuantitativa - Discreta 311 0 0.00
AREAG AREAG numeric Cuantitativa - Discreta 3 12695 30.50
SEXO SEXO numeric Cuantitativa - Discreta 3 0 0.00
DIAOCU DIAOCU numeric Cuantitativa - Discreta 31 0 0.00
MESOCU MESOCU numeric Cuantitativa - Discreta 12 0 0.00
AÑOOCU AÑOOCU numeric Cuantitativa - Discreta 11 9737 23.39
TIPAR TIPAR numeric Cuantitativa - Discreta 4 0 0.00
CLAPAR CLAPAR numeric Cuantitativa - Discreta 3 0 0.00
SEMGES SEMGES numeric Cuantitativa - Continua 67 0 0.00
EDADM EDADM numeric Cuantitativa - Continua 47 0 0.00
DEPREM DEPREM numeric Cuantitativa - Discreta 25 0 0.00
MUPREM MUPREM integer Cuantitativa - Discreta 341 0 0.00
GRETNM GRETNM numeric Cuantitativa - Discreta 3 28590 68.69
ESCIVM ESCIVM numeric Cuantitativa - Discreta 4 0 0.00
NACIOM NACIOM numeric Cuantitativa - Discreta 18 22010 52.88
OCUPAM OCUPAM numeric Cuantitativa - Discreta 72 28590 68.69
CAUDEF CAUDEF character Cualitativa - Nominal 206 0 0.00
ASISREC ASISREC numeric Cuantitativa - Discreta 6 0 0.00
SITIOOCU SITIOOCU numeric Cuantitativa - Discreta 9 0 0.00
TOHITE TOHITE numeric Cuantitativa - Discreta 21 351 0.84
TOHINM TOHINM numeric Cuantitativa - Discreta 17 142 0.34
TOHIVI TOHIVI numeric Cuantitativa - Discreta 19 258 0.62
VIAPAR VIAPAR numeric Cuantitativa - Discreta 2 3233 7.77
ESCOLAM ESCOLAM numeric Cuantitativa - Discreta 7 3233 7.77
PAISREM PAISREM numeric Cuantitativa - Discreta 6 9876 23.73
PUEBLOPM PUEBLOPM numeric Cuantitativa - Discreta 6 13033 31.31
CIUOMAD CIUOMAD character Cualitativa - Nominal 74 0 0.00
NACIONM NACIONM numeric Cuantitativa - Discreta 17 19613 47.12

2.2.3 Resumen por Tipo de Variable

resumen_tipos <- info_variables %>%
  group_by(Clasificacion) %>%
  summarise(
    Cantidad = n(),
    Porcentaje = round(n() / nrow(info_variables) * 100, 1)
  )

resumen_tipos %>%
  kable(
    caption = "Tabla 3: Distribución de Variables por Tipo",
    col.names = c("Clasificación", "Cantidad", "Porcentaje (%)"),
    align = c('l', 'r', 'r')
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = FALSE,
    position = "center"
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#2ecc71")
Tabla 3: Distribución de Variables por Tipo
Clasificación Cantidad Porcentaje (%)
Cualitativa - Nominal 2 6.1
Cuantitativa - Continua 2 6.1
Cuantitativa - Discreta 29 87.9

3 Exploración de Variables Numéricas

3.1 Medidas de Tendencia Central, Distribución y Orden

vars_numericas <- names(datos)[sapply(datos, is.numeric)]

resumen_numericas <- data.frame(
  Variable = character(),
  Media = numeric(),
  Mediana = numeric(),
  Desv_Est = numeric(),
  Min = numeric(),
  Max = numeric(),
  Q1 = numeric(),
  Q3 = numeric(),
  Asimetria = numeric(),
  Curtosis = numeric(),
  stringsAsFactors = FALSE
)

for(var in vars_numericas) {
  datos_var <- datos[[var]][!is.na(datos[[var]])]
  
  if(length(datos_var) > 0) {
    resumen_numericas <- rbind(resumen_numericas, data.frame(
      Variable = var,
      Media = mean(datos_var),
      Mediana = median(datos_var),
      Desv_Est = sd(datos_var),
      Min = min(datos_var),
      Max = max(datos_var),
      Q1 = quantile(datos_var, 0.25),
      Q3 = quantile(datos_var, 0.75),
      Asimetria = skewness(datos_var),
      Curtosis = kurtosis(datos_var)
    ))
  }
}

resumen_numericas %>%
  mutate(across(where(is.numeric), ~round(., 2))) %>%
  kable(
    caption = "Tabla 4: Estadísticas Descriptivas de Variables Numéricas",
    align = c('l', rep('r', 9))
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = TRUE,
    font_size = 11
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#e74c3c") %>%
  scroll_box(width = "100%", height = "400px")
Tabla 4: Estadísticas Descriptivas de Variables Numéricas
Variable Media Mediana Desv_Est Min Max Q1 Q3 Asimetria Curtosis
25% DEPREG 8.70 9 6.14 1 22 2 14 0.16 1.76
25%1 MUPREG 874.42 901 615.18 101 2217 201 1415 0.16 1.75
25%2 MESREG 6.47 7 3.46 1 12 3 9 -0.02 1.78
25%3 AÑOREG 2015.09 2015 3.94 2009 2023 2012 2018 0.13 1.87
25%4 DEPOCU 8.70 9 6.14 1 22 2 14 0.16 1.76
25%5 MUPOCU 874.09 901 615.00 101 2215 201 1415 0.16 1.75
25%6 AREAG 2.03 1 2.42 1 9 1 2 2.45 7.23
25%7 SEXO 1.51 1 0.71 1 9 1 2 5.32 56.57
25%8 DIAOCU 15.64 16 8.76 1 31 8 23 0.02 1.81
25%9 MESOCU 6.50 7 3.45 1 12 3 9 -0.02 1.79
25%10 AÑOOCU 1812.91 2016 605.96 9 2022 2011 2019 -2.64 7.97
25%11 TIPAR 1.45 1 1.78 1 9 1 1 3.97 16.92
25%12 CLAPAR 1.64 1 1.77 1 9 1 2 3.69 15.48
25%13 SEMGES 71.30 37 168.45 1 999 32 40 5.25 28.96
25%14 EDADM 59.42 28 162.49 10 999 22 35 5.54 32.10
25%15 DEPREM 38.56 10 456.63 1 9999 4 16 21.69 473.22
25%16 MUPREM 1802.71 1020 2704.10 101 9999 409 1609 2.55 7.98
25%17 GRETNM 4.18 2 3.65 1 9 1 9 0.54 1.34
25%18 ESCIVM 1.99 1 2.02 1 9 1 2 2.98 10.59
25%19 NACIOM 446.38 320 1202.85 31 9999 320 320 7.79 61.87
25%20 OCUPAM 9393.85 9711 1498.07 1212 9999 9711 9712 -3.85 16.65
25%21 ASISREC 2.08 1 2.04 1 9 1 3 2.19 7.28
25%22 SITIOOCU 3.39 1 2.97 1 9 1 6 0.79 2.09
25%23 TOHITE 95.79 9 217.47 0 999 3 99 3.72 15.63
25%24 TOHINM 106.83 1 262.41 0 999 1 99 3.01 10.39
25%25 TOHIVI 87.81 4 218.90 0 999 1 99 3.74 15.74
25%26 VIAPAR 1.23 1 0.42 1 2 1 1 1.27 2.62
25%27 ESCOLAM 2.67 2 2.23 1 9 1 3 1.92 5.92
25%28 PAISREM 765.77 320 2028.72 84 9999 320 320 4.33 19.76
25%29 PUEBLOPM 3.04 1 2.54 1 9 1 4 1.19 3.58
25%30 NACIONM 551.47 320 1475.61 32 9999 320 320 6.24 40.01

Interpretación de Medidas:

  • Media: Promedio aritmético de los datos
  • Mediana: Valor central que divide los datos en dos partes iguales
  • Desv. Est.: Medida de dispersión de los datos respecto a la media
  • Q1 y Q3: Primer y tercer cuartil (25% y 75% de los datos)
  • Asimetría: Indica si la distribución es simétrica (≈0), sesgada a derecha (>0) o izquierda (<0)
  • Curtosis: Indica qué tan puntiaguda es la distribución (Normal ≈ 3)

3.2 Pruebas de Normalidad

pruebas_normalidad <- data.frame(
  Variable = character(),
  n = integer(),
  Shapiro_W = numeric(),
  Shapiro_pvalor = numeric(),
  KS_estadistico = numeric(),
  KS_pvalor = numeric(),
  Es_Normal = character(),
  stringsAsFactors = FALSE
)

for(var in vars_numericas) {
  datos_var <- datos[[var]][!is.na(datos[[var]])]
  n <- length(datos_var)
  
  if(n > 3 && n < 5000) {
    shapiro_test <- shapiro.test(datos_var)
    ks_test <- ks.test(datos_var, "pnorm", mean(datos_var), sd(datos_var))
    
    es_normal <- ifelse(shapiro_test$p.value > 0.05 && ks_test$p.value > 0.05, 
                        "✓ SÍ", "✗ NO")
    
    pruebas_normalidad <- rbind(pruebas_normalidad, data.frame(
      Variable = var,
      n = n,
      Shapiro_W = shapiro_test$statistic,
      Shapiro_pvalor = shapiro_test$p.value,
      KS_estadistico = ks_test$statistic,
      KS_pvalor = ks_test$p.value,
      Es_Normal = es_normal
    ))
  }
}

pruebas_normalidad %>%
  mutate(
    Shapiro_W = round(Shapiro_W, 4),
    Shapiro_pvalor = format.pval(Shapiro_pvalor, digits = 3),
    KS_estadistico = round(KS_estadistico, 4),
    KS_pvalor = format.pval(KS_pvalor, digits = 3)
  ) %>%
  kable(
    caption = "Tabla 5: Pruebas de Normalidad (α = 0.05)",
    col.names = c("Variable", "n", "W", "p-valor", "D", "p-valor", "Normal"),
    align = c('l', 'r', 'r', 'r', 'r', 'r', 'c')
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = FALSE
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#9b59b6") %>%
  add_header_above(c(" " = 2, "Shapiro-Wilk" = 2, "Kolmogorov-Smirnov" = 2, " " = 1)) %>%
  scroll_box(width = "100%", height = "400px")
Tabla 5: Pruebas de Normalidad (α = 0.05)
Shapiro-Wilk
Kolmogorov-Smirnov
Variable n W p-valor D p-valor Normal
NA NA NA NA NA NA NA
:——– –: –: ——-: –: ——-: :——:

Interpretación:

  • Variables normales: 0 de 0
  • Variables NO normales: 0 de 0

Si p-valor < 0.05, rechazamos la hipótesis de normalidad. La mayoría de las variables no siguen una distribución normal, lo cual es común en datos de registros administrativos.

3.3 Gráficos de Normalidad

3.3.1 Gráficos Q-Q

vars_clave <- c("EDADM", "SEMGES", "AÑOREG", "MESREG", "SEXO")
vars_graficar <- vars_clave[vars_clave %in% vars_numericas]

par(mfrow = c(2, 3), mar = c(4, 4, 3, 1))

for(var in vars_graficar) {
  datos_var <- datos[[var]][!is.na(datos[[var]])]
  qqnorm(datos_var, main = paste("Q-Q Plot:", var), 
         col = "#3498db", pch = 20, cex = 0.5)
  qqline(datos_var, col = "#e74c3c", lwd = 2)
}

par(mfrow = c(1, 1))

3.3.2 Histogramas

par(mfrow = c(2, 3), mar = c(4, 4, 3, 1))

for(var in vars_graficar) {
  datos_var <- datos[[var]][!is.na(datos[[var]])]
  
  hist(datos_var, 
       probability = TRUE,
       main = paste("Histograma:", var),
       xlab = var,
       col = "#3498db",
       border = "white",
       las = 1)
  
  curve(dnorm(x, mean = mean(datos_var), sd = sd(datos_var)), 
        add = TRUE, col = "#e74c3c", lwd = 2)
  
  lines(density(datos_var), col = "#2ecc71", lwd = 2)
  
  legend("topright", 
         legend = c("Normal teórica", "Densidad real"),
         col = c("#e74c3c", "#2ecc71"), 
         lwd = 2, cex = 0.7, bty = "n")
}

par(mfrow = c(1, 1))

3.4 Tipo de Distribución

identificar_distribucion <- function(asimetria, curtosis) {
  if(abs(asimetria) < 0.5 && abs(curtosis - 3) < 0.5) {
    return("📊 Aproximadamente Normal")
  } else if(asimetria > 1) {
    return("📈 Sesgada a la derecha")
  } else if(asimetria < -1) {
    return("📉 Sesgada a la izquierda")
  } else if(curtosis > 4) {
    return("🔺 Leptocúrtica")
  } else if(curtosis < 2) {
    return("🔻 Platicúrtica")
  } else {
    return("〰️ Asimétrica")
  }
}

resumen_numericas$Tipo_Distribucion <- mapply(
  identificar_distribucion,
  resumen_numericas$Asimetria,
  resumen_numericas$Curtosis
)

resumen_numericas %>%
  select(Variable, Asimetria, Curtosis, Tipo_Distribucion) %>%
  mutate(
    Asimetria = round(Asimetria, 2),
    Curtosis = round(Curtosis, 2)
  ) %>%
  kable(
    caption = "Tabla 6: Clasificación de Distribuciones",
    col.names = c("Variable", "Asimetría", "Curtosis", "Tipo de Distribución"),
    align = c('l', 'r', 'r', 'l')
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = FALSE
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#f39c12") %>%
  scroll_box(width = "100%", height = "400px")
Tabla 6: Clasificación de Distribuciones
Variable Asimetría Curtosis Tipo de Distribución
25% DEPREG 0.16 1.76 🔻 Platicúrtica |
25%1 MUPREG 0.16 1.75 🔻 Platicúrtica |
25%2 MESREG -0.02 1.78 🔻 Platicúrtica |
25%3 AÑOREG 0.13 1.87 🔻 Platicúrtica |
25%4 DEPOCU 0.16 1.76 🔻 Platicúrtica |
25%5 MUPOCU 0.16 1.75 🔻 Platicúrtica |
25%6 AREAG 2.45 7.23 📈 Sesgada a la derecha |
25%7 SEXO 5.32 56.57 📈 Sesgada a la derecha |
25%8 DIAOCU 0.02 1.81 🔻 Platicúrtica |
25%9 MESOCU -0.02 1.79 🔻 Platicúrtica |
25%10 AÑOOCU -2.64 7.97 📉 Sesgada a la izquierda |
25%11 TIPAR 3.97 16.92 📈 Sesgada a la derecha |
25%12 CLAPAR 3.69 15.48 📈 Sesgada a la derecha |
25%13 SEMGES 5.25 28.96 📈 Sesgada a la derecha |
25%14 EDADM 5.54 32.10 📈 Sesgada a la derecha |
25%15 DEPREM 21.69 473.22 📈 Sesgada a la derecha |
25%16 MUPREM 2.55 7.98 📈 Sesgada a la derecha |
25%17 GRETNM 0.54 1.34 🔻 Platicúrtica |
25%18 ESCIVM 2.98 10.59 📈 Sesgada a la derecha |
25%19 NACIOM 7.79 61.87 📈 Sesgada a la derecha |
25%20 OCUPAM -3.85 16.65 📉 Sesgada a la izquierda |
25%21 ASISREC 2.19 7.28 📈 Sesgada a la derecha |
25%22 SITIOOCU 0.79 2.09 〰️ Asimétrica
25%23 TOHITE 3.72 15.63 📈 Sesgada a la derecha |
25%24 TOHINM 3.01 10.39 📈 Sesgada a la derecha |
25%25 TOHIVI 3.74 15.74 📈 Sesgada a la derecha |
25%26 VIAPAR 1.27 2.62 📈 Sesgada a la derecha |
25%27 ESCOLAM 1.92 5.92 📈 Sesgada a la derecha |
25%28 PAISREM 4.33 19.76 📈 Sesgada a la derecha |
25%29 PUEBLOPM 1.19 3.58 📈 Sesgada a la derecha |
25%30 NACIONM 6.24 40.01 📈 Sesgada a la derecha |

4 Exploración de Variables Categóricas

4.1 Variables Categóricas Identificadas

vars_categoricas <- c()

for(var in names(datos)) {
  if(is.character(datos[[var]])) {
    vars_categoricas <- c(vars_categoricas, var)
  } else if(is.numeric(datos[[var]])) {
    n_unicos <- length(unique(na.omit(datos[[var]])))
    if(n_unicos < 20) {
      vars_categoricas <- c(vars_categoricas, var)
    }
  }
}

Total de variables categóricas identificadas: 22

Variables: MESREG, AÑOREG, AREAG, SEXO, MESOCU, AÑOOCU, TIPAR, CLAPAR, GRETNM, ESCIVM, …

4.2 Tablas de Frecuencia

crear_tabla_frecuencias <- function(variable, nombre_var) {
  tabla <- as.data.frame(table(variable, useNA = "ifany"))
  colnames(tabla) <- c(nombre_var, "Frecuencia")
  
  tabla$Freq_Relativa <- tabla$Frecuencia / sum(tabla$Frecuencia)
  tabla$Porcentaje <- round(tabla$Freq_Relativa * 100, 2)
  tabla$Freq_Acumulada <- cumsum(tabla$Frecuencia)
  tabla$Porc_Acumulado <- round(cumsum(tabla$Freq_Relativa) * 100, 2)
  
  return(tabla)
}

4.2.1 SEXO

if("SEXO" %in% names(datos)) {
  tabla <- crear_tabla_frecuencias(datos$SEXO, "SEXO")
  
  tabla %>%
    kable(
      caption = "Tabla 7: Distribución de Frecuencias - SEXO",
      align = c('c', 'r', 'r', 'r', 'r', 'r')
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover"),
      full_width = FALSE,
      position = "center"
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#3498db")
  
  # Gráfico
  ggplot(datos, aes(x = factor(SEXO), fill = factor(SEXO))) +
    geom_bar(color = "black") +
    geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5, size = 5) +
    scale_fill_manual(values = c("#3498db", "#e74c3c", "#95a5a6")) +
    labs(
      title = "Distribución por Sexo",
      x = "Sexo (1=Masculino, 2=Femenino, 9=No especificado)",
      y = "Frecuencia"
    ) +
    theme_minimal() +
    theme(
      legend.position = "none",
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14)
    )
}

4.2.2 ASISREC

if("ASISREC" %in% names(datos)) {
  tabla <- crear_tabla_frecuencias(datos$ASISREC, "ASISREC")
  
  tabla %>%
    kable(
      caption = "Tabla 8: Distribución de Frecuencias - ASISREC (Asistencia Recibida)",
      align = c('c', 'r', 'r', 'r', 'r', 'r')
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover"),
      full_width = FALSE,
      position = "center"
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#2ecc71")
}
Tabla 8: Distribución de Frecuencias - ASISREC (Asistencia Recibida)
ASISREC Frecuencia Freq_Relativa Porcentaje Freq_Acumulada Porc_Acumulado
1 28892 0.6941355 69.41 28892 69.41
2 661 0.0158806 1.59 29553 71.00
3 6129 0.1472503 14.73 35682 85.73
4 284 0.0068232 0.68 35966 86.41
5 3490 0.0838479 8.38 39456 94.79
9 2167 0.0520626 5.21 41623 100.00

4.2.3 SITIOOCU

if("SITIOOCU" %in% names(datos)) {
  tabla <- crear_tabla_frecuencias(datos$SITIOOCU, "SITIOOCU")
  
  tabla %>%
    kable(
      caption = "Tabla 9: Distribución de Frecuencias - SITIOOCU (Sitio de Ocurrencia)",
      align = c('c', 'r', 'r', 'r', 'r', 'r')
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover"),
      full_width = FALSE,
      position = "center"
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#9b59b6")
}
Tabla 9: Distribución de Frecuencias - SITIOOCU (Sitio de Ocurrencia)
SITIOOCU Frecuencia Freq_Relativa Porcentaje Freq_Acumulada Porc_Acumulado
1 21784 0.5233645 52.34 21784 52.34
2 2335 0.0560988 5.61 24119 57.95
3 1074 0.0258030 2.58 25193 60.53
4 2229 0.0535521 5.36 27422 65.88
5 62 0.0014896 0.15 27484 66.03
6 8341 0.2003940 20.04 35825 86.07
7 18 0.0004325 0.04 35843 86.11
8 76 0.0018259 0.18 35919 86.30
9 5704 0.1370396 13.70 41623 100.00

4.2.4 CAUDEF

if("CAUDEF" %in% names(datos)) {
  tabla <- crear_tabla_frecuencias(datos$CAUDEF, "CAUDEF")
  
  # Mostrar top 20
  tabla_top20 <- head(tabla[order(-tabla$Frecuencia), ], 20)
  
  tabla_top20 %>%
    kable(
      caption = "Tabla 10: Top 20 Causas de Defunción más Frecuentes",
      align = c('l', 'r', 'r', 'r', 'r', 'r')
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover"),
      full_width = FALSE,
      position = "center"
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#e74c3c") %>%
    scroll_box(width = "100%", height = "500px")
  
  # Gráfico Top 15
  top15 <- head(tabla[order(-tabla$Frecuencia), ], 15)
  
  ggplot(top15, aes(x = reorder(CAUDEF, Frecuencia), y = Frecuencia)) +
    geom_bar(stat = "identity", fill = "#e74c3c", color = "black") +
    coord_flip() +
    geom_text(aes(label = Frecuencia), hjust = -0.2, size = 3.5) +
    labs(
      title = "Top 15 Causas de Defunción",
      x = "Código de Causa",
      y = "Frecuencia"
    ) +
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      axis.text.y = element_text(size = 10)
    )
}


5 Gráficos Exploratorios

A continuación se presentan gráficos exploratorios que permiten visualizar el estado general de los datos, identificar patrones, valores atípicos y distribuciones antes de profundizar en relaciones entre variables.

5.1 Distribución de Variables Numéricas Clave

5.1.1 Boxplots Comparativos

vars_boxplot <- c("EDADM", "SEMGES", "TOHITE", "TOHINM", "TOHIVI")
vars_boxplot <- vars_boxplot[vars_boxplot %in% names(datos)]

if(length(vars_boxplot) > 0) {
  datos_long <- datos %>%
    select(all_of(vars_boxplot)) %>%
    pivot_longer(cols = everything(), names_to = "Variable", values_to = "Valor") %>%
    filter(!is.na(Valor), Valor < 900)
  
  ggplot(datos_long, aes(x = Variable, y = Valor, fill = Variable)) +
    geom_boxplot(outlier.color = "#e74c3c", outlier.alpha = 0.3, outlier.size = 0.8) +
    stat_summary(fun = mean, geom = "point", shape = 18, size = 3, color = "black") +
    scale_fill_brewer(palette = "Set2") +
    labs(
      title = "Boxplots de Variables Numéricas Clave",
      subtitle = "Se excluyen códigos especiales (≥900). El diamante negro indica la media.",
      x = NULL, y = "Valor"
    ) +
    theme_minimal(base_size = 13) +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold"),
      plot.subtitle = element_text(hjust = 0.5, size = 10, color = "gray40"),
      legend.position = "none"
    )
}

5.1.2 Densidades Superpuestas

vars_densidad <- c("EDADM", "SEMGES")
vars_densidad <- vars_densidad[vars_densidad %in% names(datos)]

if(length(vars_densidad) > 0) {
  plots_densidad <- list()
  
  for(v in vars_densidad) {
    datos_filtrados <- datos %>%
      filter(!is.na(.data[[v]]), .data[[v]] < 900)
    
    p <- ggplot(datos_filtrados, aes(x = .data[[v]])) +
      geom_histogram(aes(y = after_stat(density)), bins = 40, 
                     fill = "#3498db", color = "white", alpha = 0.6) +
      geom_density(color = "#e74c3c", linewidth = 1.2) +
      geom_vline(aes(xintercept = mean(.data[[v]], na.rm = TRUE)), 
                 color = "#2c3e50", linetype = "dashed", linewidth = 0.8) +
      geom_vline(aes(xintercept = median(.data[[v]], na.rm = TRUE)), 
                 color = "#27ae60", linetype = "dotted", linewidth = 0.8) +
      labs(
        title = paste("Distribución de", v),
        subtitle = "Línea punteada = mediana | Línea discontinua = media",
        x = v, y = "Densidad"
      ) +
      theme_minimal(base_size = 12) +
      theme(plot.title = element_text(hjust = 0.5, face = "bold"),
            plot.subtitle = element_text(hjust = 0.5, size = 9, color = "gray40"))
    
    plots_densidad[[v]] <- p
  }
  
  do.call(grid.arrange, c(plots_densidad, ncol = length(plots_densidad)))
}

5.2 Composición de Variables Categóricas

5.2.1 Distribución por Sexo

if("SEXO" %in% names(datos)) {
  datos_sexo <- datos %>%
    filter(!is.na(SEXO)) %>%
    mutate(SEXO_label = case_when(
      SEXO == 1 ~ "Masculino",
      SEXO == 2 ~ "Femenino",
      SEXO == 9 ~ "No especificado",
      TRUE ~ as.character(SEXO)
    )) %>%
    count(SEXO_label) %>%
    mutate(porcentaje = round(n / sum(n) * 100, 1))
  
  ggplot(datos_sexo, aes(x = reorder(SEXO_label, -n), y = n, fill = SEXO_label)) +
    geom_col(width = 0.6, show.legend = FALSE) +
    geom_text(aes(label = paste0(format(n, big.mark = ","), "\n(", porcentaje, "%)")),
              vjust = -0.3, size = 4, fontface = "bold") +
    scale_fill_manual(values = c("Masculino" = "#3498db", "Femenino" = "#e91e63", 
                                 "No especificado" = "#95a5a6")) +
    labs(title = "Distribución por Sexo", x = NULL, y = "Frecuencia") +
    theme_minimal(base_size = 13) +
    theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
    scale_y_continuous(expand = expansion(mult = c(0, 0.15)))
}

5.2.2 Área Geográfica

if("AREAG" %in% names(datos)) {
  datos_area <- datos %>%
    filter(!is.na(AREAG)) %>%
    mutate(AREAG_label = case_when(
      AREAG == 1 ~ "Urbana",
      AREAG == 2 ~ "Rural",
      TRUE ~ as.character(AREAG)
    )) %>%
    count(AREAG_label) %>%
    mutate(porcentaje = round(n / sum(n) * 100, 1))
  
  ggplot(datos_area, aes(x = "", y = n, fill = AREAG_label)) +
    geom_col(width = 1) +
    coord_polar(theta = "y") +
    geom_text(aes(label = paste0(AREAG_label, "\n", porcentaje, "%")),
              position = position_stack(vjust = 0.5), size = 5, fontface = "bold") +
    scale_fill_manual(values = c("Urbana" = "#2ecc71", "Rural" = "#f39c12")) +
    labs(title = "Distribución por Área Geográfica", fill = "Área") +
    theme_void(base_size = 13) +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))
}

5.2.3 Asistencia Recibida

if("ASISREC" %in% names(datos)) {
  datos_asis <- datos %>%
    filter(!is.na(ASISREC)) %>%
    mutate(ASISREC_label = case_when(
      ASISREC == 1 ~ "Sí recibió",
      ASISREC == 2 ~ "No recibió",
      TRUE ~ as.character(ASISREC)
    )) %>%
    count(ASISREC_label) %>%
    mutate(porcentaje = round(n / sum(n) * 100, 1))
  
  ggplot(datos_asis, aes(x = reorder(ASISREC_label, -n), y = n, fill = ASISREC_label)) +
    geom_col(width = 0.5, show.legend = FALSE) +
    geom_text(aes(label = paste0(format(n, big.mark = ","), "\n(", porcentaje, "%)")),
              vjust = -0.3, size = 4, fontface = "bold") +
    scale_fill_manual(values = c("Sí recibió" = "#27ae60", "No recibió" = "#c0392b")) +
    labs(title = "Asistencia Recibida durante el Parto", x = NULL, y = "Frecuencia") +
    theme_minimal(base_size = 13) +
    theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
    scale_y_continuous(expand = expansion(mult = c(0, 0.15)))
}

5.3 Panorama Temporal

5.3.1 Registros por Año

if("AÑOREG" %in% names(datos)) {
  registros_anio <- datos %>%
    filter(!is.na(AÑOREG)) %>%
    count(AÑOREG)
  
  ggplot(registros_anio, aes(x = AÑOREG, y = n)) +
    geom_line(color = "#2c3e50", linewidth = 1) +
    geom_point(color = "#e74c3c", size = 3) +
    geom_area(alpha = 0.15, fill = "#3498db") +
    geom_text(aes(label = format(n, big.mark = ",")), vjust = -1, size = 3.2) +
    labs(
      title = "Evolución del Número de Registros por Año",
      x = "Año de Registro", y = "Cantidad de Registros"
    ) +
    scale_x_continuous(breaks = seq(min(registros_anio$AÑOREG), max(registros_anio$AÑOREG), 1)) +
    theme_minimal(base_size = 13) +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold"),
      axis.text.x = element_text(angle = 45, hjust = 1)
    ) +
    scale_y_continuous(expand = expansion(mult = c(0, 0.12)))
}

5.3.2 Distribución Mensual

if("MESOCU" %in% names(datos)) {
  meses_nombres <- c("Ene", "Feb", "Mar", "Abr", "May", "Jun",
                     "Jul", "Ago", "Sep", "Oct", "Nov", "Dic")
  
  registros_mes <- datos %>%
    filter(!is.na(MESOCU), MESOCU >= 1, MESOCU <= 12) %>%
    count(MESOCU) %>%
    mutate(Mes = factor(meses_nombres[MESOCU], levels = meses_nombres))
  
  ggplot(registros_mes, aes(x = Mes, y = n, fill = n)) +
    geom_col(show.legend = FALSE) +
    scale_fill_gradient(low = "#85c1e9", high = "#1a5276") +
    geom_text(aes(label = format(n, big.mark = ",")), vjust = -0.3, size = 3.5) +
    labs(
      title = "Distribución de Ocurrencias por Mes",
      x = "Mes de Ocurrencia", y = "Frecuencia"
    ) +
    theme_minimal(base_size = 13) +
    theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
    scale_y_continuous(expand = expansion(mult = c(0, 0.1)))
}

5.4 Detección de Valores Atípicos y Datos Faltantes

vars_revision <- c("EDADM", "SEMGES", "TOHITE", "TOHINM", "TOHIVI", "ESCOLAM")
vars_revision <- vars_revision[vars_revision %in% names(datos)]

if(length(vars_revision) > 0) {
  resumen_atipicos <- data.frame(
    Variable = character(),
    N_total = integer(),
    N_NA = integer(),
    Porc_NA = numeric(),
    N_codigo_999 = integer(),
    Porc_999 = numeric(),
    stringsAsFactors = FALSE
  )
  
  for(v in vars_revision) {
    vals <- datos[[v]]
    n_total <- length(vals)
    n_na <- sum(is.na(vals))
    n_999 <- sum(vals >= 99 & !is.na(vals))
    
    resumen_atipicos <- rbind(resumen_atipicos, data.frame(
      Variable = v,
      N_total = n_total,
      N_NA = n_na,
      Porc_NA = round(n_na / n_total * 100, 2),
      N_codigo_999 = n_999,
      Porc_999 = round(n_999 / n_total * 100, 2)
    ))
  }
  
  resumen_atipicos %>%
    kable(
      caption = "Detección de Valores Atípicos y Códigos Especiales",
      col.names = c("Variable", "N Total", "N Faltantes (NA)", "% NA", 
                     "N Códigos ≥99", "% Códigos ≥99"),
      align = c('l', rep('r', 5))
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover", "condensed"),
      full_width = FALSE
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#8e44ad")
}
Detección de Valores Atípicos y Códigos Especiales
Variable N Total N Faltantes (NA) % NA N Códigos ≥99 % Códigos ≥99
EDADM 41623 0 0.00 3429 8.24
SEMGES 41623 0 0.00 5531 13.29
TOHITE 41623 351 0.84 19353 46.50
TOHINM 41623 142 0.34 15159 36.42
TOHIVI 41623 258 0.62 16343 39.26
ESCOLAM 41623 3233 7.77 0 0.00
vars_heatmap <- names(datos)[sapply(datos, is.numeric)]

porc_faltantes <- sapply(datos[vars_heatmap], function(x) {
  na_real <- sum(is.na(x))
  cod_especial <- sum(x %in% c(99, 999, 9999) & !is.na(x))
  round((na_real + cod_especial) / length(x) * 100, 1)
})

df_faltantes <- data.frame(
  Variable = names(porc_faltantes),
  Porcentaje = as.numeric(porc_faltantes)
) %>%
  arrange(desc(Porcentaje))

ggplot(df_faltantes, aes(x = reorder(Variable, Porcentaje), y = Porcentaje, fill = Porcentaje)) +
  geom_col() +
  coord_flip() +
  scale_fill_gradient(low = "#27ae60", high = "#e74c3c", name = "% Datos\nProblema") +
  geom_text(aes(label = paste0(Porcentaje, "%")), hjust = -0.1, size = 3.5) +
  labs(
    title = "Porcentaje de Datos Faltantes o con Códigos Especiales por Variable",
    subtitle = "Incluye NA y códigos como 99, 999, 9999",
    x = NULL, y = "Porcentaje (%)"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(hjust = 0.5, size = 10, color = "gray40")
  ) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.12)))

Observaciones de los Gráficos Exploratorios:

  • 📊 Los boxplots revelan la presencia de valores extremos que probablemente corresponden a códigos de datos faltantes (99, 999, 9999)
  • 📈 Las distribuciones de densidad muestran el sesgo y la forma real de las variables clave
  • 🗓️ La tendencia temporal permite identificar cambios en el volumen de registros a lo largo de los años
  • 📅 La distribución mensual muestra si existe estacionalidad en las ocurrencias
  • ⚠️ El gráfico de datos faltantes ayuda a priorizar qué variables necesitan limpieza antes de análisis posteriores

6 Relaciones entre Variables

6.1 Análisis de Correlación

6.1.1 Matriz de Correlación

# Seleccionar variables numéricas continuas clave para correlación
vars_correlacion <- c("AÑOREG", "MESREG", "EDADM", "SEMGES", 
                      "TOHITE", "TOHINM", "TOHIVI", "ESCOLAM")

# Filtrar solo las que existen en el dataset
vars_correlacion <- vars_correlacion[vars_correlacion %in% names(datos)]

# Crear subset sin NAs
datos_corr <- datos[, vars_correlacion]
datos_corr <- na.omit(datos_corr)

# Calcular matriz de correlación
matriz_correlacion <- cor(datos_corr)

# Mostrar matriz en tabla
matriz_correlacion %>%
  round(3) %>%
  kable(
    caption = "Tabla 11: Matriz de Correlación de Pearson",
    align = 'c'
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover"),
    full_width = FALSE,
    font_size = 11
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#e74c3c")
Tabla 11: Matriz de Correlación de Pearson
AÑOREG MESREG EDADM SEMGES TOHITE TOHINM TOHIVI ESCOLAM
AÑOREG 1.000 -0.006 -0.048 -0.224 0.077 0.358 0.222 -0.025
MESREG -0.006 1.000 -0.015 -0.020 -0.010 -0.004 -0.004 -0.009
EDADM -0.048 -0.015 1.000 -0.011 0.070 0.050 0.088 0.171
SEMGES -0.224 -0.020 -0.011 1.000 -0.059 -0.107 -0.087 -0.068
TOHITE 0.077 -0.010 0.070 -0.059 1.000 0.743 0.846 0.176
TOHINM 0.358 -0.004 0.050 -0.107 0.743 1.000 0.599 0.110
TOHIVI 0.222 -0.004 0.088 -0.087 0.846 0.599 1.000 0.166
ESCOLAM -0.025 -0.009 0.171 -0.068 0.176 0.110 0.166 1.000
# Visualizar matriz de correlación
corrplot(matriz_correlacion, 
         method = "color",
         type = "upper",
         addCoef.col = "black",
         number.cex = 0.7,
         tl.col = "black",
         tl.srt = 45,
         title = "Matriz de Correlación",
         mar = c(0, 0, 2, 0))

6.1.2 Correlaciones Significativas

# Identificar correlaciones significativas (|r| > 0.3)
correlaciones_significativas <- data.frame()

for(i in 1:(ncol(matriz_correlacion)-1)) {
  for(j in (i+1):ncol(matriz_correlacion)) {
    cor_valor <- matriz_correlacion[i, j]
    if(abs(cor_valor) > 0.3) {
      correlaciones_significativas <- rbind(
        correlaciones_significativas,
        data.frame(
          Variable_1 = rownames(matriz_correlacion)[i],
          Variable_2 = colnames(matriz_correlacion)[j],
          Correlacion = cor_valor,
          Fuerza = ifelse(abs(cor_valor) > 0.7, "Fuerte",
                   ifelse(abs(cor_valor) > 0.5, "Moderada", "Débil")),
          Direccion = ifelse(cor_valor > 0, "Positiva", "Negativa")
        )
      )
    }
  }
}

# Ordenar por valor absoluto de correlación
if(nrow(correlaciones_significativas) > 0) {
  correlaciones_significativas <- correlaciones_significativas[
    order(-abs(correlaciones_significativas$Correlacion)), 
  ]
  
  correlaciones_significativas %>%
    mutate(Correlacion = round(Correlacion, 3)) %>%
    kable(
      caption = "Tabla 12: Correlaciones Significativas (|r| > 0.3)",
      col.names = c("Variable 1", "Variable 2", "r", "Fuerza", "Dirección"),
      align = c('l', 'l', 'r', 'c', 'c')
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover"),
      full_width = FALSE
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#2ecc71")
} else {
  cat("No se encontraron correlaciones significativas (|r| > 0.3)\n")
}
Tabla 12: Correlaciones Significativas (|r| > 0.3)
Variable 1 Variable 2 r Fuerza Dirección
3 TOHITE TOHIVI 0.846 Fuerte Positiva
2 TOHITE TOHINM 0.743 Fuerte Positiva
4 TOHINM TOHIVI 0.599 Moderada Positiva
1 AÑOREG TOHINM 0.358 Débil Positiva

6.2 Gráficos de Dispersión

6.2.1 Edad vs Semanas de Gestación

if("EDADM" %in% names(datos) && "SEMGES" %in% names(datos)) {
  ggplot(datos %>% filter(EDADM < 100, SEMGES < 100), 
         aes(x = EDADM, y = SEMGES)) +
    geom_point(alpha = 0.3, color = "#3498db") +
    geom_smooth(method = "lm", color = "#e74c3c", se = TRUE) +
    labs(
      title = "Relación: Edad de la Madre vs Semanas de Gestación",
      x = "Edad de la Madre (años)",
      y = "Semanas de Gestación"
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))
}

6.2.2 Edad vs Total de Hijos

if("EDADM" %in% names(datos) && "TOHITE" %in% names(datos)) {
  ggplot(datos %>% filter(EDADM < 100, TOHITE < 50), 
         aes(x = EDADM, y = TOHITE)) +
    geom_point(alpha = 0.3, color = "#2ecc71") +
    geom_smooth(method = "lm", color = "#e74c3c", se = TRUE) +
    labs(
      title = "Relación: Edad de la Madre vs Total de Hijos Tenidos",
      x = "Edad de la Madre (años)",
      y = "Total de Hijos Tenidos"
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))
}

6.2.3 Semanas vs Hijos Vivos

if("SEMGES" %in% names(datos) && "TOHIVI" %in% names(datos)) {
  ggplot(datos %>% filter(SEMGES < 100, TOHIVI < 50), 
         aes(x = SEMGES, y = TOHIVI)) +
    geom_point(alpha = 0.3, color = "#9b59b6") +
    geom_smooth(method = "lm", color = "#e74c3c", se = TRUE) +
    labs(
      title = "Relación: Semanas de Gestación vs Total de Hijos Vivos",
      x = "Semanas de Gestación",
      y = "Total de Hijos Vivos"
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))
}

6.3 Tablas de Contingencia

6.3.1 SEXO vs ASISREC

if("SEXO" %in% names(datos) && "ASISREC" %in% names(datos)) {
  # Crear tabla
  tabla_sexo_asis <- table(datos$SEXO, datos$ASISREC)
  
  # Mostrar tabla con totales
  addmargins(tabla_sexo_asis) %>%
    kable(
      caption = "Tabla 13: Tabla de Contingencia - SEXO vs ASISREC"
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover"),
      full_width = FALSE
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#3498db")
  
  # Proporciones por fila (%) - CORRECCIÓN AQUÍ
  cat("\n\nProporciones por fila (%):\n")
  
  (prop.table(tabla_sexo_asis, 1) * 100) %>%
    round(2) %>%
    kable(caption = "Porcentajes por fila") %>%
    kable_styling(bootstrap_options = c("striped", "hover")) %>%
    print()
  
  # Test de independencia Chi-cuadrado
  test_chi <- chisq.test(tabla_sexo_asis)
  
  cat("\n\n**Test de Independencia Chi-cuadrado:**\n")
  cat("- Estadístico χ²:", round(test_chi$statistic, 4), "\n")
  cat("- p-valor:", format.pval(test_chi$p.value, digits = 4), "\n")
  
  if(test_chi$p.value < 0.05) {
    cat("\n**Conclusión:** Las variables NO son independientes (p < 0.05)\n")
    cat("Existe una relación estadísticamente significativa entre SEXO y ASISREC\n")
  } else {
    cat("\n**Conclusión:** Las variables son independientes (p >= 0.05)\n")
    cat("No hay evidencia de relación entre SEXO y ASISREC\n")
  }
}
## 
## 
## Proporciones por fila (%):
## <table class="table table-striped table-hover" style="margin-left: auto; margin-right: auto;">
## <caption>Porcentajes por fila</caption>
##  <thead>
##   <tr>
##    <th style="text-align:left;">  </th>
##    <th style="text-align:right;"> 1 </th>
##    <th style="text-align:right;"> 2 </th>
##    <th style="text-align:right;"> 3 </th>
##    <th style="text-align:right;"> 4 </th>
##    <th style="text-align:right;"> 5 </th>
##    <th style="text-align:right;"> 9 </th>
##   </tr>
##  </thead>
## <tbody>
##   <tr>
##    <td style="text-align:left;"> 1 </td>
##    <td style="text-align:right;"> 68.75 </td>
##    <td style="text-align:right;"> 1.57 </td>
##    <td style="text-align:right;"> 15.22 </td>
##    <td style="text-align:right;"> 0.69 </td>
##    <td style="text-align:right;"> 8.51 </td>
##    <td style="text-align:right;"> 5.26 </td>
##   </tr>
##   <tr>
##    <td style="text-align:left;"> 2 </td>
##    <td style="text-align:right;"> 70.18 </td>
##    <td style="text-align:right;"> 1.62 </td>
##    <td style="text-align:right;"> 14.30 </td>
##    <td style="text-align:right;"> 0.68 </td>
##    <td style="text-align:right;"> 8.06 </td>
##    <td style="text-align:right;"> 5.16 </td>
##   </tr>
##   <tr>
##    <td style="text-align:left;"> 9 </td>
##    <td style="text-align:right;"> 67.54 </td>
##    <td style="text-align:right;"> 0.52 </td>
##    <td style="text-align:right;"> 1.57 </td>
##    <td style="text-align:right;"> 0.00 </td>
##    <td style="text-align:right;"> 26.18 </td>
##    <td style="text-align:right;"> 4.19 </td>
##   </tr>
## </tbody>
## </table>
## 
## 
## **Test de Independencia Chi-cuadrado:**
## - Estadístico χ²: 110.0828 
## - p-valor: < 2.2e-16 
## 
## **Conclusión:** Las variables NO son independientes (p < 0.05)
## Existe una relación estadísticamente significativa entre SEXO y ASISREC

6.3.2 SEXO vs SITIOOCU

if("SEXO" %in% names(datos) && "SITIOOCU" %in% names(datos)) {
  tabla_sexo_sitio <- table(datos$SEXO, datos$SITIOOCU)
  
  addmargins(tabla_sexo_sitio) %>%
    kable(
      caption = "Tabla 14: Tabla de Contingencia - SEXO vs SITIOOCU"
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover"),
      full_width = FALSE
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#2ecc71")
  
  # Test Chi-cuadrado
  test_chi2 <- chisq.test(tabla_sexo_sitio)
  cat("\n**Chi-cuadrado p-valor:**", format.pval(test_chi2$p.value, digits = 4), "\n")
}
## 
## **Chi-cuadrado p-valor:** < 2.2e-16

6.3.3 AREAG vs ASISREC

if("AREAG" %in% names(datos) && "ASISREC" %in% names(datos)) {
  tabla_area_asis <- table(datos$AREAG, datos$ASISREC)
  
  addmargins(tabla_area_asis) %>%
    kable(
      caption = "Tabla 15: Tabla de Contingencia - AREAG vs ASISREC"
    ) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover"),
      full_width = FALSE
    ) %>%
    row_spec(0, bold = TRUE, color = "white", background = "#9b59b6")
  
  # Test Chi-cuadrado
  test_chi3 <- chisq.test(tabla_area_asis)
  cat("\n**Chi-cuadrado p-valor:**", format.pval(test_chi3$p.value, digits = 4), "\n")
  
  if(test_chi3$p.value < 0.05) {
    cat("\n**Conclusión:** El área geográfica SÍ influye en la asistencia recibida (p < 0.05)\n")
  } else {
    cat("\n**Conclusión:** El área geográfica NO influye significativamente en la asistencia (p >= 0.05)\n")
  }
}
## 
## **Chi-cuadrado p-valor:** < 2.2e-16 
## 
## **Conclusión:** El área geográfica SÍ influye en la asistencia recibida (p < 0.05)

6.4 Visualizaciones de Relaciones

6.4.1 Barras Agrupadas

if("SEXO" %in% names(datos) && "ASISREC" %in% names(datos)) {
  datos_graf <- datos %>%
    filter(!is.na(SEXO) & !is.na(ASISREC) & SEXO %in% c(1, 2)) %>%
    mutate(
      Sexo = factor(SEXO, levels = c(1, 2), 
                    labels = c("Masculino", "Femenino")),
      Asistencia = factor(ASISREC, levels = c(1, 2),
                         labels = c("Sí recibió", "No recibió"))
    ) %>%
    group_by(Sexo, Asistencia) %>%
    summarise(Frecuencia = n(), .groups = "drop")
  
  ggplot(datos_graf, aes(x = Sexo, y = Frecuencia, fill = Asistencia)) +
    geom_bar(stat = "identity", position = "dodge", color = "black") +
    geom_text(aes(label = Frecuencia), 
              position = position_dodge(width = 0.9),
              vjust = -0.5, size = 3.5) +
    scale_fill_manual(values = c("#2ecc71", "#e74c3c")) +
    labs(
      title = "Asistencia Recibida por Sexo",
      x = "Sexo",
      y = "Frecuencia",
      fill = "Asistencia"
    ) +
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      legend.position = "top"
    )
}

6.4.2 Boxplots por Grupo

# Boxplot: Edad de la Madre por Sexo del bebé
if("EDADM" %in% names(datos) && "SEXO" %in% names(datos)) {
  datos_box <- datos %>%
    filter(EDADM < 100 & SEXO %in% c(1, 2)) %>%
    mutate(Sexo = factor(SEXO, levels = c(1, 2), 
                        labels = c("Masculino", "Femenino")))
  
  ggplot(datos_box, aes(x = Sexo, y = EDADM, fill = Sexo)) +
    geom_boxplot(alpha = 0.7) +
    scale_fill_manual(values = c("#3498db", "#e74c3c")) +
    labs(
      title = "Distribución de Edad de la Madre por Sexo del Bebé",
      x = "Sexo del Bebé",
      y = "Edad de la Madre (años)"
    ) +
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold"),
      legend.position = "none"
    )
}

6.4.3 Tendencia Temporal

if("AÑOREG" %in% names(datos)) {
  tendencia_anual <- datos %>%
    group_by(AÑOREG) %>%
    summarise(
      Total_Registros = n(),
      Edad_Promedio = mean(EDADM, na.rm = TRUE),
      Semanas_Promedio = mean(SEMGES, na.rm = TRUE)
    ) %>%
    filter(AÑOREG >= 2009 & AÑOREG <= 2023)
  
  # Gráfico de tendencia
  ggplot(tendencia_anual, aes(x = AÑOREG, y = Total_Registros)) +
    geom_line(color = "#3498db", size = 1.2) +
    geom_point(color = "#e74c3c", size = 3) +
    labs(
      title = "Tendencia de Registros por Año",
      x = "Año",
      y = "Número de Registros"
    ) +
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold"),
      axis.text.x = element_text(angle = 45, hjust = 1)
    ) +
    scale_x_continuous(breaks = seq(2009, 2023, 1))
}

6.5 Resumen de Relaciones

cat("\n")
cat("========================================\n")
## ========================================
cat("RESUMEN DE RELACIONES ENTRE VARIABLES\n")
## RESUMEN DE RELACIONES ENTRE VARIABLES
cat("========================================\n\n")
## ========================================
cat("**CORRELACIONES:**\n")
## **CORRELACIONES:**
cat("--------------\n")
## --------------
if(exists("correlaciones_significativas") && nrow(correlaciones_significativas) > 0) {
  cat("✓ Se encontraron", nrow(correlaciones_significativas), 
      "correlaciones significativas (|r| > 0.3)\n")
  cat("  - Correlación más fuerte: r =", 
      round(max(abs(correlaciones_significativas$Correlacion)), 3), "\n\n")
} else {
  cat("✗ No se encontraron correlaciones fuertes entre variables numéricas\n\n")
}
## ✓ Se encontraron 4 correlaciones significativas (|r| > 0.3)
##   - Correlación más fuerte: r = 0.846
cat("**ASOCIACIONES CATEGÓRICAS:**\n")
## **ASOCIACIONES CATEGÓRICAS:**
cat("-------------------------\n")
## -------------------------
cat("✓ Se analizaron múltiples tablas de contingencia\n")
## ✓ Se analizaron múltiples tablas de contingencia
cat("✓ Se aplicaron pruebas Chi-cuadrado para independencia\n\n")
## ✓ Se aplicaron pruebas Chi-cuadrado para independencia
cat("**HALLAZGOS PRINCIPALES:**\n")
## **HALLAZGOS PRINCIPALES:**
cat("----------------------\n")
## ----------------------
cat("1. Relación entre edad de la madre y total de hijos tenidos\n")
## 1. Relación entre edad de la madre y total de hijos tenidos
cat("2. Posible influencia del área geográfica en la asistencia recibida\n")
## 2. Posible influencia del área geográfica en la asistencia recibida
cat("3. Tendencia temporal observable en el número de registros\n")
## 3. Tendencia temporal observable en el número de registros
cat("4. Distribución relativamente equilibrada entre sexos\n")
## 4. Distribución relativamente equilibrada entre sexos

7 Preguntas de Investigación Basadas en Supuestos

A continuación se plantean cinco hipótesis preliminares basadas en creencias intuitivas sobre el fenómeno estudiado. Cada una será validada o refutada mediante análisis estadístico y visualización.

7.1 Pregunta 1

7.1.1 Hipótesis

Las madres que viven en área rural reciben menos asistencia durante el parto que las que viven en área urbana.

7.1.2 Analisis

# Tabla de contingencia
tabla_area_asis <- table(datos$AREAG, datos$ASISREC)

# Proporciones por fila
prop_area_asis <- prop.table(tabla_area_asis, 1) * 100

kable(round(prop_area_asis,2),
      caption = "Porcentaje de Asistencia por Área Geográfica")
Porcentaje de Asistencia por Área Geográfica
1 2 3 4 5 9
1 92.51 0.42 2.20 0.17 2.17 2.53
2 3.30 0.90 72.34 2.65 17.71 3.10
9 27.68 12.25 2.13 1.02 8.42 48.51
# Prueba Chi-cuadrado
chisq_area_asis <- chisq.test(tabla_area_asis)
chisq_area_asis
## 
##  Pearson's Chi-squared test
## 
## data:  tabla_area_asis
## X-squared = 31911, df = 10, p-value < 2.2e-16

7.1.3 Interpretación

7.1.4 Discusión

7.2 Pregunta 2

7.2.1 Hipótesis

Las madres de mayor edad tienden a tener más hijos.

7.2.2 Analisis

cor.test(datos$EDADM, datos$TOHITE, use = "complete.obs")
## 
##  Pearson's product-moment correlation
## 
## data:  datos$EDADM and datos$TOHITE
## t = 14.602, df = 41270, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.06208668 0.08128286
## sample estimates:
##        cor 
## 0.07169141
ggplot(datos %>% filter(EDADM < 60, TOHITE < 20),
       aes(x = EDADM, y = TOHITE)) +
  geom_point(alpha = 0.3) +
  geom_smooth(method = "lm", color = "red") +
  theme_minimal() +
  labs(title = "Edad vs Total de Hijos")

7.2.3 Interpretación

7.2.4 Discusión

7.3 Pregunta 3

7.3.1 Hipótesis

Existe estacionalidad en las ocurrencias (algunos meses concentran más casos).

7.3.2 Analisis

registros_mes <- datos %>%
  filter(MESOCU >=1 & MESOCU <=12) %>%
  count(MESOCU)

ggplot(registros_mes, aes(x = MESOCU, y = n)) +
  geom_col(fill = "steelblue") +
  theme_minimal() +
  labs(title = "Distribución mensual de ocurrencias")

7.3.3 Interpretación

7.3.4 Discusión

7.4 Pregunta 4

7.4.1 Hipótesis

Las madres con menor nivel educativo tienen más hijos.

7.4.2 Analisis

cor.test(datos$ESCOLAM, datos$TOHITE, use = "complete.obs")
## 
##  Pearson's product-moment correlation
## 
## data:  datos$ESCOLAM and datos$TOHITE
## t = 34.925, df = 38037, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  0.1665179 0.1859921
## sample estimates:
##       cor 
## 0.1762722
ggplot(datos %>% filter(ESCOLAM < 20, TOHITE < 20),
       aes(x = ESCOLAM, y = TOHITE)) +
  geom_point(alpha = 0.3) +
  geom_smooth(method = "lm", color = "red") +
  theme_minimal() +
  labs(title = "Escolaridad vs Total de Hijos")

7.4.3 Interpretación

7.4.4 Discusión

7.5 Pregunta 5

7.5.1 Hipótesis

El sitio de ocurrencia influye en la asistencia recibida.

7.5.2 Analisis

tabla_sitio_asis <- table(datos$SITIOOCU, datos$ASISREC)
chisq.test(tabla_sitio_asis)
## 
##  Pearson's Chi-squared test
## 
## data:  tabla_sitio_asis
## X-squared = 56621, df = 40, p-value < 2.2e-16

7.5.3 Interpretación

7.5.4 Discusión

8 Clustering

El objetivo del clustering es identificar grupos homogéneos de registros según características similares.

8.1 Selección de Variables

Usaremos variables numéricas relevantes:

EDADM (edad madre)

SEMGES (semanas gestación)

TOHITE (total hijos)

ESCOLAM (escolaridad)

8.2 Preparacion de variables y generación de clusters

library(cluster)

datos_cluster <- datos %>%
  select(EDADM, SEMGES, TOHITE, ESCOLAM) %>%
  filter(
    EDADM < 60,
    SEMGES < 50,
    TOHITE < 20,
    ESCOLAM < 20
  ) %>%
  na.omit()

# Estandarización
datos_scaled <- scale(datos_cluster)

wss <- numeric(10)

for(i in 1:10){
  wss[i] <- sum(kmeans(datos_scaled, centers=i, nstart=10)$withinss)
}

plot(1:10, wss, type="b",
     xlab="Número de clusters",
     ylab="Suma de cuadrados intra-grupo")

set.seed(123)
k3 <- kmeans(datos_scaled, centers=3, nstart=25)

datos_cluster$cluster <- factor(k3$cluster)

ggplot(datos_cluster, aes(x=EDADM, y=TOHITE, color=cluster)) +
  geom_point(alpha=0.6) +
  theme_minimal() +
  labs(title="Clusters según Edad y Número de Hijos")

aggregate(datos_cluster[,1:4],
          by=list(Cluster=datos_cluster$cluster),
          mean)

8.3 Interpretación de clusters

El método del codo indicó que el número óptimo de grupos es k = 3, ya que a partir de este punto la reducción en la suma de cuadrados intra-grupo se estabiliza, indicando rendimientos decrecientes al aumentar el número de clusters.

El análisis de medias permitió identificar tres perfiles diferenciados:

Cluster 1 (Perfil intermedio educado): Madres con edad promedio de 29 años, nivel educativo medio (≈9 años) y número moderado de hijos (≈3.8). Representa un grupo con características intermedias tanto en edad como en fecundidad.

Cluster 2 (Perfil joven con baja escolaridad): Grupo más joven (≈26 años), con bajo nivel educativo (≈2 años) y menor número de hijos (≈2.7). Puede representar madres en etapa inicial reproductiva y en situación de vulnerabilidad educativa.

Cluster 3 (Perfil de mayor edad y alta fecundidad): Madres de mayor edad (≈36 años), con el mayor número promedio de hijos (≈6.3) y el nivel educativo más bajo (≈1.5 años). Este grupo refleja un patrón de alta fecundidad asociado a baja escolaridad.

Los resultados sugieren una relación estructural entre edad, escolaridad y número de hijos, donde niveles educativos más bajos se asocian con mayor fecundidad. El clustering permitió identificar perfiles poblacionales claramente diferenciados, lo cual puede ser relevante para el diseño de políticas públicas focalizadas.


9 Documentación de Operaciones de Limpieza de Datos

A lo largo del análisis exploratorio se aplicaron diversas operaciones de limpieza y filtrado para garantizar la calidad y coherencia de los resultados. A continuación se documenta cada una de ellas de forma estructurada.

9.1 Resumen de Operaciones de Limpieza

operaciones_limpieza <- data.frame(
  No = 1:10,
  Operacion = c(
    "Eliminación de valores NA (na.omit / !is.na)",
    "Exclusión de códigos especiales ≥ 900",
    "Filtro de edad de la madre (EDADM < 100)",
    "Filtro de semanas de gestación (SEMGES < 100)",
    "Filtro de total hijos tenidos (TOHITE < 50)",
    "Filtro de total hijos vivos (TOHIVI < 50)",
    "Validación de meses (MESOCU entre 1 y 12)",
    "Exclusión de sexo no especificado (SEXO ∈ {1, 2})",
    "Acotamiento del rango temporal (2009-2023)",
    "Identificación de códigos 99, 999, 9999 como datos faltantes"
  ),
  Justificacion = c(
    "Los registros con valores faltantes (NA) fueron excluidos en cálculos estadísticos, gráficos y tablas de frecuencia para evitar distorsiones en medias, medianas, correlaciones y pruebas de normalidad.",
    "Variables como EDADM, SEMGES, TOHITE, TOHINM y TOHIVI utilizan códigos numéricos altos (≥ 900) para representar información no disponible. Estos valores fueron excluidos en boxplots y gráficos de densidad para que las distribuciones reflejen solo datos reales.",
    "Se excluyeron registros con EDADM ≥ 100 ya que estos valores corresponden a códigos de datos faltantes (99, 999) y no a edades reales. La edad máxima biológicamente plausible para una madre es menor a 60 años.",
    "Se excluyeron registros con SEMGES ≥ 100 ya que representan códigos de datos faltantes, no semanas de gestación reales. El rango biológico válido es aproximadamente entre 20 y 42 semanas.",
    "Se excluyeron registros con TOHITE ≥ 50 para eliminar códigos especiales de datos faltantes. Es biológicamente improbable que una persona tenga 50 o más hijos.",
    "Se excluyeron registros con TOHIVI ≥ 50 bajo el mismo criterio de plausibilidad biológica y para eliminar códigos especiales.",
    "Se filtraron solo meses válidos (1 a 12), descartando valores fuera de rango que podrían representar errores de digitación o códigos especiales.",
    "En análisis de contingencia y boxplots comparativos se excluyó el código 9 (no especificado) de la variable SEXO para enfocarse en las categorías informativas (1=Masculino, 2=Femenino).",
    "Se acotó el análisis de tendencia temporal al período 2009-2023, que corresponde al rango de años con datos completos y consistentes del dataset.",
    "Los códigos numéricos 99, 999 y 9999 fueron identificados como representaciones de datos faltantes o no especificados en el sistema de registro. Se contabilizaron para medir la calidad de los datos."
  ),
  Variables_Afectadas = c(
    "Todas las variables numéricas y categóricas",
    "EDADM, SEMGES, TOHITE, TOHINM, TOHIVI",
    "EDADM",
    "SEMGES",
    "TOHITE",
    "TOHIVI",
    "MESOCU",
    "SEXO",
    "AÑOREG",
    "EDADM, SEMGES, TOHITE, TOHINM, TOHIVI, ESCOLAM"
  ),
  Seccion_Aplicada = c(
    "Estadísticas descriptivas, pruebas de normalidad, correlaciones, tablas de frecuencia, gráficos",
    "Boxplots comparativos, gráficos de densidad",
    "Gráficos de dispersión (Edad vs Semanas, Edad vs Hijos), boxplots por grupo",
    "Gráficos de dispersión (Edad vs Semanas, Semanas vs Hijos Vivos)",
    "Gráfico de dispersión (Edad vs Total Hijos)",
    "Gráfico de dispersión (Semanas vs Hijos Vivos)",
    "Gráfico de distribución mensual de ocurrencias",
    "Barras agrupadas (Sexo vs Asistencia), boxplots por grupo",
    "Gráfico de tendencia temporal",
    "Detección de valores atípicos, heatmap de datos faltantes"
  ),
  stringsAsFactors = FALSE
)

operaciones_limpieza %>%
  kable(
    caption = "Tabla: Documentación Completa de Operaciones de Limpieza de Datos",
    col.names = c("#", "Operación", "Justificación", "Variables Afectadas", "Sección Aplicada"),
    align = c('c', 'l', 'l', 'l', 'l')
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = TRUE,
    font_size = 11
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#d35400") %>%
  column_spec(2, width = "15em") %>%
  column_spec(3, width = "25em") %>%
  scroll_box(width = "100%", height = "600px")
Tabla: Documentación Completa de Operaciones de Limpieza de Datos
# Operación Justificación Variables Afectadas Sección Aplicada
1 Eliminación de valores NA (na.omit / !is.na) Los registros con valores faltantes (NA) fueron excluidos en cálculos estadísticos, gráficos y tablas de frecuencia para evitar distorsiones en medias, medianas, correlaciones y pruebas de normalidad. Todas las variables numéricas y categóricas Estadísticas descriptivas, pruebas de normalidad, correlaciones, tablas de frecuencia, gráficos
2 Exclusión de códigos especiales ≥ 900 Variables como EDADM, SEMGES, TOHITE, TOHINM y TOHIVI utilizan códigos numéricos altos (≥ 900) para representar información no disponible. Estos valores fueron excluidos en boxplots y gráficos de densidad para que las distribuciones reflejen solo datos reales. EDADM, SEMGES, TOHITE, TOHINM, TOHIVI Boxplots comparativos, gráficos de densidad
3 Filtro de edad de la madre (EDADM < 100) Se excluyeron registros con EDADM ≥ 100 ya que estos valores corresponden a códigos de datos faltantes (99, 999) y no a edades reales. La edad máxima biológicamente plausible para una madre es menor a 60 años. EDADM Gráficos de dispersión (Edad vs Semanas, Edad vs Hijos), boxplots por grupo
4 Filtro de semanas de gestación (SEMGES < 100) Se excluyeron registros con SEMGES ≥ 100 ya que representan códigos de datos faltantes, no semanas de gestación reales. El rango biológico válido es aproximadamente entre 20 y 42 semanas. SEMGES Gráficos de dispersión (Edad vs Semanas, Semanas vs Hijos Vivos)
5 Filtro de total hijos tenidos (TOHITE < 50) Se excluyeron registros con TOHITE ≥ 50 para eliminar códigos especiales de datos faltantes. Es biológicamente improbable que una persona tenga 50 o más hijos. TOHITE Gráfico de dispersión (Edad vs Total Hijos)
6 Filtro de total hijos vivos (TOHIVI < 50) Se excluyeron registros con TOHIVI ≥ 50 bajo el mismo criterio de plausibilidad biológica y para eliminar códigos especiales. TOHIVI Gráfico de dispersión (Semanas vs Hijos Vivos)
7 Validación de meses (MESOCU entre 1 y 12) Se filtraron solo meses válidos (1 a 12), descartando valores fuera de rango que podrían representar errores de digitación o códigos especiales. MESOCU Gráfico de distribución mensual de ocurrencias
8 Exclusión de sexo no especificado (SEXO ∈ {1, 2}) En análisis de contingencia y boxplots comparativos se excluyó el código 9 (no especificado) de la variable SEXO para enfocarse en las categorías informativas (1=Masculino, 2=Femenino). SEXO Barras agrupadas (Sexo vs Asistencia), boxplots por grupo
9 Acotamiento del rango temporal (2009-2023) Se acotó el análisis de tendencia temporal al período 2009-2023, que corresponde al rango de años con datos completos y consistentes del dataset. AÑOREG Gráfico de tendencia temporal
10 Identificación de códigos 99, 999, 9999 como datos faltantes Los códigos numéricos 99, 999 y 9999 fueron identificados como representaciones de datos faltantes o no especificados en el sistema de registro. Se contabilizaron para medir la calidad de los datos. EDADM, SEMGES, TOHITE, TOHINM, TOHIVI, ESCOLAM Detección de valores atípicos, heatmap de datos faltantes

9.2 Impacto Cuantitativo de la Limpieza

n_total <- nrow(datos)

impacto <- data.frame(
  Filtro = c(
    "Registros originales",
    "NA en EDADM",
    "NA en SEMGES",
    "EDADM ≥ 100 (códigos especiales)",
    "SEMGES ≥ 100 (códigos especiales)",
    "TOHITE ≥ 50 (códigos especiales)",
    "TOHIVI ≥ 50 (códigos especiales)",
    "SEXO = 9 (no especificado)",
    "MESOCU fuera de rango (1-12)",
    "Códigos 99/999/9999 en cualquier variable numérica"
  ),
  Registros_Afectados = c(
    n_total,
    sum(is.na(datos$EDADM)),
    sum(is.na(datos$SEMGES)),
    if("EDADM" %in% names(datos)) sum(datos$EDADM >= 100, na.rm = TRUE) else 0,
    if("SEMGES" %in% names(datos)) sum(datos$SEMGES >= 100, na.rm = TRUE) else 0,
    if("TOHITE" %in% names(datos)) sum(datos$TOHITE >= 50, na.rm = TRUE) else 0,
    if("TOHIVI" %in% names(datos)) sum(datos$TOHIVI >= 50, na.rm = TRUE) else 0,
    if("SEXO" %in% names(datos)) sum(datos$SEXO == 9, na.rm = TRUE) else 0,
    if("MESOCU" %in% names(datos)) sum(datos$MESOCU < 1 | datos$MESOCU > 12, na.rm = TRUE) else 0,
    sum(sapply(datos[sapply(datos, is.numeric)], function(x) sum(x %in% c(99, 999, 9999), na.rm = TRUE)))
  ),
  stringsAsFactors = FALSE
)

impacto$Porcentaje <- round(impacto$Registros_Afectados / n_total * 100, 2)
impacto$Porcentaje[1] <- 100.00

impacto %>%
  mutate(Registros_Afectados = format(Registros_Afectados, big.mark = ",")) %>%
  kable(
    caption = "Tabla: Impacto Cuantitativo de cada Operación de Limpieza",
    col.names = c("Filtro / Condición", "Registros Afectados", "% del Total"),
    align = c('l', 'r', 'r')
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE,
    position = "center"
  ) %>%
  row_spec(0, bold = TRUE, color = "white", background = "#d35400") %>%
  row_spec(1, bold = TRUE, background = "#f0f0f0")
Tabla: Impacto Cuantitativo de cada Operación de Limpieza
Filtro / Condición Registros Afectados % del Total
Registros originales 41,623 100.00
NA en EDADM 0 0.00
NA en SEMGES 0 0.00
EDADM ≥ 100 (códigos especiales) 1,195 2.87
SEMGES ≥ 100 (códigos especiales) 1,310 3.15
TOHITE ≥ 50 (códigos especiales) 19,353 46.50
TOHIVI ≥ 50 (códigos especiales) 16,343 39.26
SEXO = 9 (no especificado) 191 0.46
MESOCU fuera de rango (1-12) 0 0.00
Códigos 99/999/9999 en cualquier variable numérica 75,016 180.23

Notas Importantes sobre la Limpieza:

  • ⚠️ Los datos originales no fueron modificados. Todas las operaciones de limpieza se aplicaron como filtros temporales dentro de cada análisis específico, preservando la integridad del dataset original.
  • 🔢 Códigos especiales: Los valores 99, 999 y 9999 son convenciones del sistema de registro de defunciones para indicar “dato no especificado” o “dato no disponible”.
  • 📊 Criterio de exclusión: Los umbrales utilizados (EDADM < 100, SEMGES < 100, TOHITE < 50, TOHIVI < 50) fueron seleccionados considerando los rangos biológicamente plausibles de cada variable.
  • 🔄 Reproducibilidad: Cada filtro está implementado directamente en el bloque de código R correspondiente, lo que garantiza la reproducibilidad completa del análisis.

10 Conclusiones

10.1 Hallazgos Principales

10.1.1 1. Descripción General del Dataset

  • ✓ Dataset con 41,623 observaciones y 33 variables
  • ✓ Período de análisis: 2009-2023
  • ✓ Variables clasificadas en cuantitativas (discretas/continuas) y cualitativas (nominales)
  • ✓ Significado de cada variable documentado en el diccionario de datos

10.1.2 2. Variables Numéricas

  • 📊 Se analizaron 31 variables numéricas
  • ✗ La mayoría NO siguen distribución normal (según pruebas de Shapiro-Wilk y Kolmogorov-Smirnov)
  • 📈 Predominan distribuciones sesgadas a la derecha
  • ⚠️ Se detectan valores atípicos (códigos 999, 9999) que representan datos faltantes
  • 📉 Variables como EDADM y SEMGES presentan valores extremos que requieren limpieza

10.1.3 3. Variables Categóricas

  • ✓ Se identificaron 22 variables categóricas
  • 📊 Tablas de frecuencia generadas para variables clave (SEXO, ASISREC, SITIOOCU, CAUDEF)
  • 📈 CAUDEF muestra alta variabilidad de causas de defunción
  • 👥 La distribución por sexo es relativamente balanceada

10.1.4 4. Relaciones entre Variables

  • 🔗 Matriz de correlación calculada para variables numéricas clave
  • 📊 Se identificaron correlaciones significativas entre algunas variables
  • ✓ Pruebas de independencia Chi-cuadrado aplicadas a variables categóricas
  • 📈 Relación observable entre edad de la madre y total de hijos
  • 🏥 Posible influencia del área geográfica (urbana/rural) en la asistencia recibida
  • 📅 Tendencia temporal en el número de registros a lo largo de los años

10.1.5 Recomendaciones para Análisis Posteriores

  1. Limpieza de datos: Convertir códigos especiales (999, 9999, 99) a valores NA
  2. Transformaciones: Considerar transformación logarítmica para variables con sesgo pronunciado
  3. Análisis multivariado: Explorar modelos de regresión para relaciones más complejas
  4. Análisis geoespacial: Investigar patrones regionales por departamento y municipio
  5. Series temporales: Analizar tendencias y estacionalidad en los datos
  6. Análisis de supervivencia: Estudiar factores asociados con causas de defunción

11 Información de Sesión

sessionInfo()
## R version 4.3.1 (2023-06-16)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS 26.2
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: America/Guatemala
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] cluster_2.1.4    corrplot_0.95    gridExtra_2.3    kableExtra_1.4.0
##  [5] knitr_1.50       ggplot2_3.4.2    nortest_1.0-4    moments_0.14.1  
##  [9] tidyr_1.3.0      dplyr_1.1.2     
## 
## loaded via a namespace (and not attached):
##  [1] sass_0.4.10        utf8_1.2.3         generics_0.1.3     xml2_1.3.8        
##  [5] lattice_0.21-8     stringi_1.7.12     digest_0.6.33      magrittr_2.0.3    
##  [9] evaluate_1.0.4     grid_4.3.1         RColorBrewer_1.1-3 fastmap_1.2.0     
## [13] Matrix_1.5-4.1     jsonlite_2.0.0     mgcv_1.8-42        purrr_1.0.1       
## [17] fansi_1.0.4        viridisLite_0.4.2  scales_1.2.1       textshaping_1.0.1 
## [21] jquerylib_0.1.4    cli_3.6.1          rlang_1.1.1        splines_4.3.1     
## [25] munsell_0.5.0      withr_2.5.0        cachem_1.1.0       yaml_2.3.10       
## [29] tools_4.3.1        colorspace_2.1-0   vctrs_0.6.3        R6_2.5.1          
## [33] lifecycle_1.0.3    stringr_1.5.0      pkgconfig_2.0.3    pillar_1.9.0      
## [37] bslib_0.9.0        gtable_0.3.3       glue_1.6.2         systemfonts_1.2.3 
## [41] xfun_0.52          tibble_3.2.1       tidyselect_1.2.1   rstudioapi_0.17.1 
## [45] farver_2.1.1       nlme_3.1-162       htmltools_0.5.8.1  rmarkdown_2.29    
## [49] svglite_2.2.1      labeling_0.4.2     compiler_4.3.1

Fin del Análisis Exploratorio

Documento generado el 16 de February de 2026 a las 00:45:57